/***
  cifrador.java is part of Marioneta.

  Marioneta is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License.

  Marioneta is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
  
  @author martin
   Martin Edmundo Barriga Orozco, 2008
   martin.barriga@gulmore.org
  
  cifrador: La funcion de esta clase es facilitar los procesos de encriptacion
  de Strings. Maneja llaves que se pueden adaptar a dos tipos de cifrado 
 */

package escritorioremoto;

import java.security.MessageDigest;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.NoSuchPaddingException;
import java.security.NoSuchAlgorithmException;
import java.security.InvalidKeyException;
import java.io.UnsupportedEncodingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.BadPaddingException;

public class cifrador {
    private SecretKey key;
    private Cipher cipher;
    private String texto_plano;
    private String texto_cifrado;
    private String tipo_algoritmo;
    
    public String getMD5(String texto){
        return getHash(texto, "MD5");
    }
    
    public String getSHA(String texto){
        return getHash(texto, "SHA");
    }
    
    private String getHash(String texto, String tipo){
        StringBuffer hexString = new StringBuffer();
        try{
           MessageDigest m = MessageDigest.getInstance(tipo);
           m.reset();
           //Hacer resumen con el parametro enviado al metodo
           m.update( texto.getBytes() );
           byte[] resumen = m.digest();
           
           //Convertimos el resumen a formato de base 16
           for (int i=0; i < resumen.length; i++) {
	      hexString.append(Integer.toHexString(0xFF & resumen[i]));
           }
        }
        catch(NoSuchAlgorithmException e ){
           System.out.println("Exepcion getHash: No hay implementacion " + tipo);
        }
        return hexString.toString();
    }
    
    //El constructor se encarga de inicializar
    public cifrador(String tipo, SecretKey key){
        //Inicializacion de miembros clase
        tipo_algoritmo = tipo;
        texto_plano = "";
        texto_cifrado = "";
        this.key = key;
        
        //Iniciamos el Cipher en modo encriptacion
        this.setCipherVal(true);
    }
    
    //El constructor se encarga de inicializar y generar llave
    public cifrador(String tipo){
        //Inicializacion de miembros clase
        tipo_algoritmo = tipo;
        texto_plano = "";
        texto_cifrado = "";
        
        try{
            //Creacion de la llave a usar
            key = KeyGenerator.getInstance( tipo_algoritmo ).generateKey();
        }
        catch(NoSuchAlgorithmException e ){
           System.out.println("Exepcion hacer_cifrado: No hay implementacion " +  tipo + ", en el cifrador o generador  de llaves");
        }
        
        //Iniciamos el Cipher en modo encriptacion
        this.setCipherVal(true);
    }
    
    //Comenzar pruebas con tipo = DES
    public String cifrado_hacer( String texto ){
        StringBuffer str_cifrado = new StringBuffer();
        texto_plano = texto;

        try{
            this.setCipherVal(true);
                                  
            byte[] noshow = this.cipher.doFinal( texto_plano.getBytes("UTF8") );
            
            for(int i=0; i < noshow.length; i++){ 
                //Apagamos los bit-basura para enviar lo que sirve a la cadena
                String tmp = Integer.toHexString(  noshow[i] & 0x000000ff );
                if ( tmp.length() < 2 ){
                    if ( tmp.length() == 1 )
                        tmp = "0" + tmp;
                    else
                        tmp = "00";
                }
                str_cifrado.append( tmp );
            }
        }
        catch( UnsupportedEncodingException e ){
            System.out.println("Excepcion hacer_cifrado: codificacion utf8 no soportada");
        }
        catch( IllegalBlockSizeException e ){
            //doFInal(byte[])
            System.out.println("Excepcion hacer_cifrado: codificacion utf8 no soportada");
        }
        catch( BadPaddingException e ){
            //doFinal
            System.out.println("Excepcion hacer_cifrado: " + e.getMessage());
        }
        texto_cifrado = str_cifrado.toString();
        return str_cifrado.toString();
    }
    
    public String cifrado_deshacer( String texto ){
        String str_utf8 = "";
        
        try{
            this.setCipherVal(false);
            
            byte[] soporte = new byte[ texto.length()/2 ];
            
            int cont = 0;
            for(int i=0; i < texto.length() ; i+=2 ){
                String tmp = "0x" + texto.substring(i, i + 2);
                
                //Acemos dos cast pues no podemos  enviar directamente a byte
                short s = Short.decode(tmp);
                soporte[cont++] =  (byte) ( (byte) s );
            } 
            
            byte[] utf8 = cipher.doFinal( soporte );
            
            String exito = new String( utf8, "UTF8" );
            str_utf8 = exito;
        }
        catch( UnsupportedEncodingException e ){
            //new String(utf8, "UTF8");
            System.out.println("Excepcion cifrado_deshacer: codificacion utf8 no soportada");
        }
        catch( BadPaddingException e ){
            //doFinal
            System.out.println("Excepcion cifrado_deshacer: " + e.getMessage() );
        }
        catch( IllegalBlockSizeException e ){
            //doFInal(byte[])
            System.out.println("Excepcion cifrado_deshacer: codificacion utf8 no soportada");
        }
        return str_utf8;
    }
    
    public void setCipherVal( boolean encripta ){
        try{
           cipher = Cipher.getInstance( tipo_algoritmo );
           if ( encripta == true )
               cipher.init(Cipher.ENCRYPT_MODE, key);
           else
               cipher.init(Cipher.DECRYPT_MODE, key);
        }
        catch( InvalidKeyException e ){
            //Cipher.init
            System.out.println("Excepcion setCipherVal: Llave invalida");
        }
        catch(NoSuchPaddingException e ){
            //getInstance
            System.out.println("Excepcion setCipherVal: Objeto Cipher creado incorrectamente");
        }
        catch(NoSuchAlgorithmException e ){
            //getInstance
            System.out.println("Exepcion setCipherVal: No hay implementacion " +  tipo_algoritmo + ", en el cifrador o generador  de llaves");
        }
    }
    
    public Cipher getCipher(){
        return  this.cipher;
    }
     
    public SecretKey getLlave(){
        return key;
    }
    
    public void setLlave( SecretKey key ){
        this.key = key;
    }
    
    public String getTextoCifrado(){
       return texto_cifrado; 
    }
    
    public String getTextoPlano(){
        return texto_plano;
    }
    
    public static void main(String[] args) {
        
    }
}